SVG 格式是什么?SVG 格式是一种基于可扩展标记语言(XML)的矢量图形格式,全称为可伸缩矢量图形(Scalable Vector Graphics)。SVG 图像在放大或缩小时能够保持图形质量,常用于网站图标、图表、动画等。
理论上 SVG 可以无损的放大到任意尺寸。
http://samherbert.net/svg-loaders/
我拿最后一个做的实验。
因为不熟悉 SVG 的语法, 我让GPT 帮我做了。 我的Prompt是:
x1```
2<svg width="57" height="57" viewBox="0 0 57 57" xmlns="http://www.w3.org/2000/svg" stroke="#fff">
3<g fill="none" fill-rule="evenodd">
4<g transform="translate(1 1)" stroke-width="2">
5<circle cx="5" cy="50" r="5">
6<animate attributeName="cy" begin="0s" dur="2.2s" values="50;5;50;50" calcMode="linear" repeatCount="indefinite"/>
7<animate attributeName="cx" begin="0s" dur="2.2s" values="5;27;49;5" calcMode="linear" repeatCount="indefinite"/>
8</circle>
9<circle cx="27" cy="5" r="5">
10<animate attributeName="cy" begin="0s" dur="2.2s" from="5" to="5" values="5;50;50;5" calcMode="linear" repeatCount="indefinite"/>
11<animate attributeName="cx" begin="0s" dur="2.2s" from="27" to="27" values="27;49;5;27" calcMode="linear" repeatCount="indefinite"/>
12</circle>
13<circle cx="49" cy="50" r="5">
14<animate attributeName="cy" begin="0s" dur="2.2s" values="50;50;5;50" calcMode="linear" repeatCount="indefinite"/>
15<animate attributeName="cx" from="49" to="49" begin="0s" dur="2.2s" values="49;5;27;49" calcMode="linear" repeatCount="indefinite"/>
16</circle>
17</g>
18</g>
19</svg>
20```
21
22using python to turn this animate svg to a serial of static svgs (contains with 256 frames):
我给的 Prompt 是 256 帧。改成其他也行。
这是 GPT 给我的代码:
xxxxxxxxxx
471from xml.etree import ElementTree as ET
2
3from wand.image import Image
4
5# SVG template with placeholders for cx and cy attributes for each circle
6svg_template = '''<svg width="57" height="57" viewBox="0 0 57 56" xmlns="http://www.w3.org/2000/svg" stroke="#7be827">
7 <g fill="none" fill-rule="evenodd">
8 <g transform="translate(1 1)" stroke-width="2">
9 <circle cx="{cx1}" cy="{cy1}" r="5"/>
10 <circle cx="{cx2}" cy="{cy2}" r="5"/>
11 <circle cx="{cx3}" cy="{cy3}" r="5"/>
12 </g>
13 </g>
14</svg>'''
15
16# Function to calculate the position of a circle at a given time
17def calculate_position(t, duration, values):
18 # Linear interpolation between values
19 values = [float(v) for v in values.split(';')]
20 total_values = len(values)
21 step_duration = duration / (total_values - 1)
22 step_index = int(t // step_duration)
23 progress = (t % step_duration) / step_duration
24 return values[step_index] + progress * (values[(step_index + 1) % total_values] - values[step_index])
25
26# Total frames desired
27total_frames = 256
28# Animation duration
29duration = 2.2
30
31for frame in range(total_frames):
32 t = (duration * frame) / total_frames
33
34 # Calculate positions for each circle
35 cx1 = calculate_position(t, duration, "5;27;49;5")
36 cy1 = calculate_position(t, duration, "50;5;50;50")
37 cx2 = calculate_position(t, duration, "27;49;5;27")
38 cy2 = calculate_position(t, duration, "5;50;50;5")
39 cx3 = calculate_position(t, duration, "49;5;27;49")
40 cy3 = calculate_position(t, duration, "50;50;5;50")
41
42 # Create frame SVG
43 frame_svg = svg_template.format(cx1=cx1, cy1=cy1, cx2=cx2, cy2=cy2, cx3=cx3, cy3=cy3)
44
45 # Save svg frame to disk
46 with open(f'frames/{frame:03d}.svg', 'w') as f:
47 f.write(frame_svg)
这是生成的 SVG:
将生成 SVG Frames 转成 png 用的是 “inkscape.exe”, 我试过几个原生Python 方案, 效果都不理想, 有系统原因跑不起来, 也有转换后丢失通明通道的关系。
这是代码:
x
1def svg2png(svg):
2 png = svg.replace('.svg', '.png')
3 command= f'"C:\\Program Files\\Inkscape\\bin\\inkscape.exe" -o {png} -w 10240 {svg}'
4 print(f"running {command}")
5 try:
6 check_call(command, shell=True)
7 print(f'convert one channel to')
8 except Exception as e:
9 print('An error occurred:', e)
10
11def convert_svg_frames_to_png():
12 for svg_filename in glob.glob('frames/*.svg'):
13 svg2png(svg_filename)
14
15convert_svg_frames_to_png()
这是生成的 png
来看看 svg 转成的 10K png 有多清晰。
ffmpeg -r 2 -i frames\%03d.png -c:v libx264 -profile:v high -pix_fmt yuv420p -y out.mp4
这是合成出来的视频video 浏览器,以及大多数的播放器应该都播放不了。
P.S.
遇到的坑:
合成出来 10K视频用普通播放器播放不了。 我一度以为什么 视频编码的问题, 其实并不是。 最后,成功用ffplay 播放出来了.